package processor;

import java.util.HashMap;
import java.util.List;
import java.util.StringTokenizer;

import bean.rule.RuleCondition;
import bean.rule.RuleParameter;


public class RuleProcessor {

	
	
	private HashMap<String, RuleParameter> mapRuleParameters = new HashMap<String, RuleParameter>();
	
	public RuleProcessor( List<RuleParameter> ruleParameters){
			
		for(RuleParameter rp : ruleParameters){
			try{
				mapRuleParameters.put(rp.getShortName(), rp);
			}catch(Exception ex){
				
			}
		}		
	}	
	
	public RuleParameter getRuleParameter(String paramName){
		return mapRuleParameters.get(paramName);
	}
	
	public String getParamType(String paramName){
		return mapRuleParameters.get(paramName).getParamType();
	}
	
	public String getParamLongName(String paramName){
		return mapRuleParameters.get(paramName).getLongName();
	}
	
	public RiskFactor checkRuleCondition(RuleCondition ruleCondition, Object paramValue){
		String operator = ruleCondition.getOperator();
		String paramType = this.getParamType(ruleCondition.getParameter());
		///////////////////////////////Integer////////////////////////////////
		if(paramType.equalsIgnoreCase("Integer")){
			Integer actualVal = (Integer)paramValue;
			if(operator.equals(">")){
				Integer idealVal = Integer.parseInt(ruleCondition.getValue());
				System.out.println("actualValue:"+actualVal+", idealValue:"+idealVal);
				if(actualVal == 0){
					return new RiskFactor(Result.NOT_AVAILABLE, this.getParamLongName(ruleCondition.getParameter()), "If value ABOVE threshold value " + idealVal);
				}else
				if(actualVal > idealVal){
					
					double amountOfChange = Math.abs(actualVal-idealVal)*1.0/(idealVal * 1.0);					
					return new RiskFactor(this.getParamLongName(ruleCondition.getParameter()),
							"High", "Value ABOVE threshold value " + idealVal,ruleCondition.getCriticality(),amountOfChange,Result.TRUE);
				}else {
					return new RiskFactor(Result.FALSE);
				}
				
			}
			if(operator.equals(">=")){
				Integer idealVal = Integer.parseInt(ruleCondition.getValue());
				System.out.println("actualValue:"+actualVal+", idealValue:"+idealVal);
				if(actualVal == 0){
					return new RiskFactor(Result.NOT_AVAILABLE, this.getParamLongName(ruleCondition.getParameter()),"If value ABOVE threshold value " + idealVal);
				}else
				if(actualVal >= idealVal){
					
					double amountOfChange = Math.abs(actualVal-idealVal)*1.0/(idealVal * 1.0);
					return new RiskFactor(this.getParamLongName(ruleCondition.getParameter()),
							"High", "Value ABOVE threshold value " + idealVal,ruleCondition.getCriticality(),amountOfChange,Result.TRUE);
				}else{
					return new RiskFactor(Result.FALSE);
				}
			}
			if(operator.equals("<")){
				Integer idealVal = Integer.parseInt(ruleCondition.getValue());
				System.out.println("actualValue:"+actualVal+", idealValue:"+idealVal);
				if(actualVal == 0){
					 return new RiskFactor(Result.NOT_AVAILABLE, this.getParamLongName(ruleCondition.getParameter()),"If value BELOW threshold value " + idealVal);
				}else
				if(actualVal < idealVal){
					
					double amountOfChange = Math.abs(actualVal-idealVal)*1.0/(idealVal * 1.0);
					return new RiskFactor(this.getParamLongName(ruleCondition.getParameter()),
							"Low", "Value BELOW threshold value " + idealVal,ruleCondition.getCriticality(),amountOfChange,Result.TRUE);
				}else{
					return new RiskFactor(Result.FALSE);
				}
			}
			if(operator.equals("<=")){
				Integer idealVal = Integer.parseInt(ruleCondition.getValue());
				System.out.println("actualValue:"+actualVal+", idealValue:"+idealVal);
				if(actualVal == 0){
					return new RiskFactor(Result.NOT_AVAILABLE, this.getParamLongName(ruleCondition.getParameter()),"If value BELOW threshold value " + idealVal);
				}else
				if(actualVal <= idealVal){
					
					double amountOfChange = Math.abs(actualVal-idealVal)*1.0/(idealVal * 1.0);
					return new RiskFactor(this.getParamLongName(ruleCondition.getParameter()),
							"Low", "Value BELOW threshold value " + idealVal,ruleCondition.getCriticality(),amountOfChange,Result.TRUE);
				}else {
					return new RiskFactor(Result.FALSE);
				}
			}
			
			if(operator.equals("=")){
				Integer idealVal = Integer.parseInt(ruleCondition.getValue());
				System.out.println("actualValue:"+actualVal+", idealValue:"+idealVal);
				if(actualVal == 0){
					return new RiskFactor(Result.NOT_AVAILABLE, this.getParamLongName(ruleCondition.getParameter()),"If value is " + idealVal);
				}else
				if(actualVal == idealVal){
					
					double amountOfChange = 1.0;
					return new RiskFactor(this.getParamLongName(ruleCondition.getParameter()),
							"Abnormal","Value is " + idealVal, ruleCondition.getCriticality(),amountOfChange,Result.TRUE);
				}else {
					return new RiskFactor(Result.FALSE);
				}
			}
			
			if(operator.equals("range")){
				StringTokenizer tokenizer = new StringTokenizer(ruleCondition.getValue(), "-");
				int i=0;
				int startValue=0, endValue=0;
				while(tokenizer.hasMoreTokens()){
					if(i==0){
						startValue = Integer.parseInt(tokenizer.nextToken().trim());
						i++;
					}else{
						endValue = Integer.parseInt(tokenizer.nextToken().trim());
					}
				}
				
				if(actualVal == 0){
					return new RiskFactor(Result.NOT_AVAILABLE, this.getParamLongName(ruleCondition.getParameter()), "If value BETWEEN " + startValue +" and "+ endValue);
				}else if(actualVal >= startValue && actualVal <= endValue){
					if(actualVal>=startValue){
						double amountOfChange = Math.abs(actualVal-startValue)*1.0/(startValue * 1.0);
						return new RiskFactor(this.getParamLongName(ruleCondition.getParameter()),
								"High","Value ABOVE threshold value " + startValue,ruleCondition.getCriticality(),amountOfChange,Result.TRUE);
					}
					if(actualVal <= endValue){
						double amountOfChange = Math.abs(actualVal-endValue)*1.0/(endValue * 1.0);
						return new RiskFactor(this.getParamLongName(ruleCondition.getParameter()),
								"Low", "Value ABOVE threshold value " + startValue, ruleCondition.getCriticality(),amountOfChange,Result.TRUE);
					}
				}else{
					return new RiskFactor(Result.FALSE);
				}
			}
			
		}
		/////////////////////////////Double////////////////////////////////
		else if(paramType.equalsIgnoreCase("Double")){
			Double actualVal = (Double)paramValue;
			if(operator.equals(">")){
				Double idealVal = Double.parseDouble(ruleCondition.getValue());
				System.out.println("actualValue:"+actualVal+", idealValue:"+idealVal);
				if(actualVal == 0){
					return new RiskFactor(Result.NOT_AVAILABLE, this.getParamLongName(ruleCondition.getParameter()),"If value ABOVE threshold value " + idealVal);
				}else if(actualVal > idealVal){
					double amountOfChange = Math.abs(actualVal-idealVal)*1.0/(idealVal * 1.0);
					return new RiskFactor(this.getParamLongName(ruleCondition.getParameter()),
							"High", "Value ABOVE threshold value " + idealVal, ruleCondition.getCriticality(),amountOfChange,Result.TRUE);
				}else {
					return new RiskFactor(Result.FALSE);
				}
			}
			if(operator.equals(">=")){
				Double idealVal = Double.parseDouble(ruleCondition.getValue());
				System.out.println("actualValue:"+actualVal+", idealValue:"+idealVal);
				if(actualVal == 0){
					return new RiskFactor(Result.NOT_AVAILABLE, this.getParamLongName(ruleCondition.getParameter()),"If value ABOVE threshold value " + idealVal);
				}else if(actualVal >= idealVal){
					double amountOfChange = Math.abs(actualVal-idealVal)*1.0/(idealVal * 1.0);
					return new RiskFactor(this.getParamLongName(ruleCondition.getParameter()),
							"High", "Value ABOVE threshold value " + idealVal, ruleCondition.getCriticality(),amountOfChange,Result.TRUE);
				}else {
					return new RiskFactor(Result.FALSE);
				}
			}
			if(operator.equals("<")){
				Double idealVal = Double.parseDouble(ruleCondition.getValue());
				System.out.println("actualValue:"+actualVal+", idealValue:"+idealVal);
				if(actualVal == 0){
					return new RiskFactor(Result.NOT_AVAILABLE, this.getParamLongName(ruleCondition.getParameter()),"If value BELOW threshold value " + idealVal);
				}else if(actualVal < idealVal){
					double amountOfChange = Math.abs(actualVal-idealVal)*1.0/(idealVal * 1.0);
					return new RiskFactor(this.getParamLongName(ruleCondition.getParameter()),
							"Low", "Value BELOW threshold value " + idealVal, ruleCondition.getCriticality(),amountOfChange,Result.TRUE);
				}else {
					return new RiskFactor(Result.FALSE);
				}
			}
			if(operator.equals("<=")){
				Double idealVal = Double.parseDouble(ruleCondition.getValue());
				System.out.println("actualValue:"+actualVal+", idealValue:"+idealVal);
				if(actualVal == 0){
					return new RiskFactor(Result.NOT_AVAILABLE, this.getParamLongName(ruleCondition.getParameter()), "If value BELOW threshold value " + idealVal);
				}else if(actualVal <= idealVal){
					double amountOfChange = Math.abs(actualVal-idealVal)*1.0/(idealVal * 1.0);
					return new RiskFactor(this.getParamLongName(ruleCondition.getParameter()),
							"Low", "Value BELOW threshold value " + idealVal, ruleCondition.getCriticality(),amountOfChange,Result.TRUE);
				}else{
					return new RiskFactor(Result.FALSE);
				}
			}
			
			if(operator.equals("=")){
				Double idealVal = Double.parseDouble(ruleCondition.getValue());
				System.out.println("actualValue:"+actualVal+", idealValue:"+idealVal);
				if(actualVal == 0){
					return new RiskFactor(Result.NOT_AVAILABLE, this.getParamLongName(ruleCondition.getParameter()),"If value is " + idealVal);
				}else if(actualVal == idealVal){
					double amountOfChange = 1.0;
					return new RiskFactor(this.getParamLongName(ruleCondition.getParameter()),
							"Abnormal", "Value equal to " + idealVal, ruleCondition.getCriticality(),amountOfChange,Result.TRUE);
				}else {
					return new RiskFactor(Result.FALSE);
				}
			}
			
			if(operator.equals("range")){
				StringTokenizer tokenizer = new StringTokenizer(ruleCondition.getValue(), "-");
				int i=0;
				double startValue=0, endValue=0;
				while(tokenizer.hasMoreTokens()){
					if(i==0){
						startValue = Double.parseDouble(tokenizer.nextToken().trim());
						i++;
					}else{
						endValue = Double.parseDouble(tokenizer.nextToken().trim());
					}
				}
				if(actualVal == 0){
					return new RiskFactor(Result.NOT_AVAILABLE, this.getParamLongName(ruleCondition.getParameter()), "If value BETWEEN " + startValue +" and " + endValue);
				}else if(actualVal >= startValue && actualVal <= endValue){
					if(actualVal>=startValue){
						double amountOfChange = Math.abs(actualVal-startValue)*1.0/(startValue * 1.0);
						return new RiskFactor(this.getParamLongName(ruleCondition.getParameter()),
								"High","Value ABOVE threshold value " + startValue, ruleCondition.getCriticality(),amountOfChange,Result.TRUE);
					}
					if(actualVal <= endValue){
						double amountOfChange = Math.abs(actualVal-endValue)*1.0/(endValue * 1.0);
						return new RiskFactor(this.getParamLongName(ruleCondition.getParameter()),
								"Low", "Value ABOVE threshold value " + startValue, ruleCondition.getCriticality(),amountOfChange,Result.TRUE);
					}
				}else {
					return new RiskFactor(Result.FALSE);
				}
			}
		}
		/////////////////////////////String////////////////////////////////
		else if(paramType.equalsIgnoreCase("String")){
			String actualVal = (String)paramValue;
			if(operator.equals("=")){
				String idealVal = ruleCondition.getValue();
				if(actualVal == null){
					return new RiskFactor(Result.NOT_AVAILABLE, this.getParamLongName(ruleCondition.getParameter()), "If value is " + idealVal);
				}else if(actualVal.equalsIgnoreCase(idealVal)){
					
					double amountOfChange = 1.0;
					return new RiskFactor(this.getParamLongName(ruleCondition.getParameter()),
							"Abnormal", "Value equal to " + idealVal, ruleCondition.getCriticality(),amountOfChange,Result.TRUE);
				}else {
					return new RiskFactor(Result.FALSE);
				}
			}
		}
		/////////////////////////////Boolean////////////////////////////////
		else if(paramType.equalsIgnoreCase("Boolean")){
			Boolean actualVal = (Boolean)paramValue;
			
			if(operator.equals("=")){
				Boolean idealVal = Boolean.parseBoolean(ruleCondition.getValue());
				System.out.println("actualValue:"+actualVal+", idealValue:"+idealVal);
				if(actualVal == null){
					return new RiskFactor(Result.NOT_AVAILABLE, this.getParamLongName(ruleCondition.getParameter()), "If value is " + idealVal);
				}else
				if(actualVal == idealVal){
					double amountOfChange = 1.0;
					return new RiskFactor(this.getParamLongName(ruleCondition.getParameter()),
							"Abnormal", "Value is " + idealVal, ruleCondition.getCriticality(),amountOfChange,Result.TRUE);
				}else {
					return new RiskFactor(Result.FALSE);
				}
			}
			
		}
		
		return new RiskFactor(Result.FALSE);
	}
	
	
	public String getParameterSource(String paramName){
		return mapRuleParameters.get(paramName).getSource();
		
	}
}
